// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"

#include <algorithm>

#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"

using ::testing::_;
using ::testing::Eq;
using ::testing::Invoke;
using ::testing::Mock;
using ::testing::Sequence;
using ::testing::StrictMock;
using ::testing::Values;

namespace quic {
namespace test {
namespace {

// Header Acknowledgement decoder stream instruction with stream_id = 1.
const char* const kHeaderAcknowledgement = "\x81";

const uint64_t kMaximumDynamicTableCapacity = 1024;
const uint64_t kMaximumBlockedStreams = 1;

class QpackDecoderTest : public QuicTestWithParam<FragmentMode> {
 protected:
  QpackDecoderTest()
      : qpack_decoder_(kMaximumDynamicTableCapacity,
                       kMaximumBlockedStreams,
                       &encoder_stream_error_delegate_),
        fragment_mode_(GetParam()) {
    qpack_decoder_.set_qpack_stream_sender_delegate(
        &decoder_stream_sender_delegate_);
  }

  ~QpackDecoderTest() override = default;

  void SetUp() override {
    // Destroy QpackProgressiveDecoder on error to test that it does not crash.
    // See https://crbug.com/1025209.
    ON_CALL(handler_, OnDecodingErrorDetected(_))
        .WillByDefault(
            Invoke([this](quiche::QuicheStringPiece /* error_message */) {
              progressive_decoder_.reset();
            }));
  }

  void DecodeEncoderStreamData(quiche::QuicheStringPiece data) {
    qpack_decoder_.encoder_stream_receiver()->Decode(data);
  }

  std::unique_ptr<QpackProgressiveDecoder> CreateProgressiveDecoder(
      QuicStreamId stream_id) {
    return qpack_decoder_.CreateProgressiveDecoder(stream_id, &handler_);
  }

  // Set up |progressive_decoder_|.
  void StartDecoding() {
    progressive_decoder_ = CreateProgressiveDecoder(/* stream_id = */ 1);
  }

  // Pass header block data to QpackProgressiveDecoder::Decode()
  // in fragments dictated by |fragment_mode_|.
  void DecodeData(quiche::QuicheStringPiece data) {
    auto fragment_size_generator =
        FragmentModeToFragmentSizeGenerator(fragment_mode_);
    while (progressive_decoder_ && !data.empty()) {
      size_t fragment_size = std::min(fragment_size_generator(), data.size());
      progressive_decoder_->Decode(data.substr(0, fragment_size));
      data = data.substr(fragment_size);
    }
  }

  // Signal end of header block to QpackProgressiveDecoder.
  void EndDecoding() {
    if (progressive_decoder_) {
      progressive_decoder_->EndHeaderBlock();
    }
    // If no error was detected, |*progressive_decoder_| is kept alive so that
    // it can handle callbacks later in case of blocked decoding.
  }

  // Decode an entire header block.
  void DecodeHeaderBlock(quiche::QuicheStringPiece data) {
    StartDecoding();
    DecodeData(data);
    EndDecoding();
  }

  StrictMock<MockEncoderStreamErrorDelegate> encoder_stream_error_delegate_;
  StrictMock<MockQpackStreamSenderDelegate> decoder_stream_sender_delegate_;
  StrictMock<MockHeadersHandler> handler_;

 private:
  QpackDecoder qpack_decoder_;
  const FragmentMode fragment_mode_;
  std::unique_ptr<QpackProgressiveDecoder> progressive_decoder_;
};

INSTANTIATE_TEST_SUITE_P(All,
                         QpackDecoderTest,
                         Values(FragmentMode::kSingleChunk,
                                FragmentMode::kOctetByOctet));

TEST_P(QpackDecoderTest, NoPrefix) {
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("Incomplete header data prefix.")));

  // Header Data Prefix is at least two bytes long.
  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("00"));
}

// Regression test for https://1025209: QpackProgressiveDecoder must not crash
// in Decode() if it is destroyed by handler_.OnDecodingErrorDetected().
TEST_P(QpackDecoderTest, InvalidPrefix) {
  StartDecoding();

  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("Encoded integer too large.")));

  // Encoded Required Insert Count in Header Data Prefix is too large.
  DecodeData(
      quiche::QuicheTextUtils::HexDecode("ffffffffffffffffffffffffffff"));
}

TEST_P(QpackDecoderTest, EmptyHeaderBlock) {
  EXPECT_CALL(handler_, OnDecodingCompleted());

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("0000"));
}

TEST_P(QpackDecoderTest, LiteralEntryEmptyName) {
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("foo")));
  EXPECT_CALL(handler_, OnDecodingCompleted());

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("00002003666f6f"));
}

TEST_P(QpackDecoderTest, LiteralEntryEmptyValue) {
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
  EXPECT_CALL(handler_, OnDecodingCompleted());

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("000023666f6f00"));
}

TEST_P(QpackDecoderTest, LiteralEntryEmptyNameAndValue) {
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("")));
  EXPECT_CALL(handler_, OnDecodingCompleted());

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("00002000"));
}

TEST_P(QpackDecoderTest, SimpleLiteralEntry) {
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
  EXPECT_CALL(handler_, OnDecodingCompleted());

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("000023666f6f03626172"));
}

TEST_P(QpackDecoderTest, MultipleLiteralEntries) {
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
  std::string str(127, 'a');
  EXPECT_CALL(handler_,
              OnHeaderDecoded(Eq("foobaar"), quiche::QuicheStringPiece(str)));
  EXPECT_CALL(handler_, OnDecodingCompleted());

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0000"                // prefix
      "23666f6f03626172"    // foo: bar
      "2700666f6f62616172"  // 7 octet long header name, the smallest number
                            // that does not fit on a 3-bit prefix.
      "7f0061616161616161"  // 127 octet long header value, the smallest number
      "616161616161616161"  // that does not fit on a 7-bit prefix.
      "6161616161616161616161616161616161616161616161616161616161616161616161"
      "6161616161616161616161616161616161616161616161616161616161616161616161"
      "6161616161616161616161616161616161616161616161616161616161616161616161"
      "616161616161"));
}

// Name Length value is too large for varint decoder to decode.
TEST_P(QpackDecoderTest, NameLenTooLargeForVarintDecoder) {
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("Encoded integer too large.")));

  DecodeHeaderBlock(
      quiche::QuicheTextUtils::HexDecode("000027ffffffffffffffffffff"));
}

// Name Length value can be decoded by varint decoder but exceeds 1 MB limit.
TEST_P(QpackDecoderTest, NameLenExceedsLimit) {
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("String literal too long.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("000027ffff7f"));
}

// Value Length value is too large for varint decoder to decode.
TEST_P(QpackDecoderTest, ValueLenTooLargeForVarintDecoder) {
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("Encoded integer too large.")));

  DecodeHeaderBlock(
      quiche::QuicheTextUtils::HexDecode("000023666f6f7fffffffffffffffffffff"));
}

// Value Length value can be decoded by varint decoder but exceeds 1 MB limit.
TEST_P(QpackDecoderTest, ValueLenExceedsLimit) {
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("String literal too long.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("000023666f6f7fffff7f"));
}

TEST_P(QpackDecoderTest, IncompleteHeaderBlock) {
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("Incomplete header block.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("00002366"));
}

TEST_P(QpackDecoderTest, HuffmanSimple) {
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")));
  EXPECT_CALL(handler_, OnDecodingCompleted());

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"));
}

TEST_P(QpackDecoderTest, AlternatingHuffmanNonHuffman) {
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")))
      .Times(4);
  EXPECT_CALL(handler_, OnDecodingCompleted());

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0000"                        // Prefix.
      "2f0125a849e95ba97d7f"        // Huffman-encoded name.
      "8925a849e95bb8e8b4bf"        // Huffman-encoded value.
      "2703637573746f6d2d6b6579"    // Non-Huffman encoded name.
      "0c637573746f6d2d76616c7565"  // Non-Huffman encoded value.
      "2f0125a849e95ba97d7f"        // Huffman-encoded name.
      "0c637573746f6d2d76616c7565"  // Non-Huffman encoded value.
      "2703637573746f6d2d6b6579"    // Non-Huffman encoded name.
      "8925a849e95bb8e8b4bf"));     // Huffman-encoded value.
}

TEST_P(QpackDecoderTest, HuffmanNameDoesNotHaveEOSPrefix) {
  EXPECT_CALL(handler_, OnDecodingErrorDetected(quiche::QuicheStringPiece(
                            "Error in Huffman-encoded string.")));

  // 'y' ends in 0b0 on the most significant bit of the last byte.
  // The remaining 7 bits must be a prefix of EOS, which is all 1s.
  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "00002f0125a849e95ba97d7e8925a849e95bb8e8b4bf"));
}

TEST_P(QpackDecoderTest, HuffmanValueDoesNotHaveEOSPrefix) {
  EXPECT_CALL(handler_, OnDecodingErrorDetected(quiche::QuicheStringPiece(
                            "Error in Huffman-encoded string.")));

  // 'e' ends in 0b101, taking up the 3 most significant bits of the last byte.
  // The remaining 5 bits must be a prefix of EOS, which is all 1s.
  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "00002f0125a849e95ba97d7f8925a849e95bb8e8b4be"));
}

TEST_P(QpackDecoderTest, HuffmanNameEOSPrefixTooLong) {
  EXPECT_CALL(handler_, OnDecodingErrorDetected(quiche::QuicheStringPiece(
                            "Error in Huffman-encoded string.")));

  // The trailing EOS prefix must be at most 7 bits long.  Appending one octet
  // with value 0xff is invalid, even though 0b111111111111111 (15 bits) is a
  // prefix of EOS.
  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "00002f0225a849e95ba97d7fff8925a849e95bb8e8b4bf"));
}

TEST_P(QpackDecoderTest, HuffmanValueEOSPrefixTooLong) {
  EXPECT_CALL(handler_, OnDecodingErrorDetected(quiche::QuicheStringPiece(
                            "Error in Huffman-encoded string.")));

  // The trailing EOS prefix must be at most 7 bits long.  Appending one octet
  // with value 0xff is invalid, even though 0b1111111111111 (13 bits) is a
  // prefix of EOS.
  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "00002f0125a849e95ba97d7f8a25a849e95bb8e8b4bfff"));
}

TEST_P(QpackDecoderTest, StaticTable) {
  // A header name that has multiple entries with different values.
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("POST")));
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("TRACE")));

  // A header name that has a single entry with non-empty value.
  EXPECT_CALL(handler_,
              OnHeaderDecoded(Eq("accept-encoding"), Eq("gzip, deflate, br")));
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("accept-encoding"), Eq("compress")));
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("accept-encoding"), Eq("")));

  // A header name that has a single entry with empty value.
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("location"), Eq("")));
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("location"), Eq("foo")));

  EXPECT_CALL(handler_, OnDecodingCompleted());

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0000d1dfccd45f108621e9aec2a11f5c8294e75f000554524143455f1000"));
}

TEST_P(QpackDecoderTest, TooHighStaticTableIndex) {
  // This is the last entry in the static table with index 98.
  EXPECT_CALL(handler_,
              OnHeaderDecoded(Eq("x-frame-options"), Eq("sameorigin")));

  // Addressing entry 99 should trigger an error.
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("Static table entry not found.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("0000ff23ff24"));
}

TEST_P(QpackDecoderTest, DynamicTable) {
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode(
      "3fe107"          // Set dynamic table capacity to 1024.
      "6294e703626172"  // Add literal entry with name "foo" and value "bar".
      "80035a5a5a"      // Add entry with name of dynamic table entry index 0
                        // (relative index) and value "ZZZ".
      "cf8294e7"        // Add entry with name of static table entry index 15
                        // and value "foo".
      "01"));           // Duplicate entry with relative index 1.

  // Now there are four entries in the dynamic table.
  // Entry 0: "foo", "bar"
  // Entry 1: "foo", "ZZZ"
  // Entry 2: ":method", "foo"
  // Entry 3: "foo", "ZZZ"

  // Use a Sequence to test that mock methods are called in order.
  Sequence s;

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar"))).InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("foo")))
      .InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
  EXPECT_CALL(decoder_stream_sender_delegate_,
              WriteStreamData(Eq(kHeaderAcknowledgement)))
      .InSequence(s);
  EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0500"  // Required Insert Count 4 and Delta Base 0.
              // Base is 4 + 0 = 4.
      "83"    // Dynamic table entry with relative index 3, absolute index 0.
      "82"    // Dynamic table entry with relative index 2, absolute index 1.
      "81"    // Dynamic table entry with relative index 1, absolute index 2.
      "80"    // Dynamic table entry with relative index 0, absolute index 3.
      "41025a5a"));  // Name of entry 1 (relative index) from dynamic table,
                     // with value "ZZ".

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar"))).InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("foo")))
      .InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
  EXPECT_CALL(decoder_stream_sender_delegate_,
              WriteStreamData(Eq(kHeaderAcknowledgement)))
      .InSequence(s);
  EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0502"  // Required Insert Count 4 and Delta Base 2.
              // Base is 4 + 2 = 6.
      "85"    // Dynamic table entry with relative index 5, absolute index 0.
      "84"    // Dynamic table entry with relative index 4, absolute index 1.
      "83"    // Dynamic table entry with relative index 3, absolute index 2.
      "82"    // Dynamic table entry with relative index 2, absolute index 3.
      "43025a5a"));  // Name of entry 3 (relative index) from dynamic table,
                     // with value "ZZ".

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar"))).InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("foo")))
      .InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
  EXPECT_CALL(decoder_stream_sender_delegate_,
              WriteStreamData(Eq(kHeaderAcknowledgement)))
      .InSequence(s);
  EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0582"  // Required Insert Count 4 and Delta Base 2 with sign bit set.
              // Base is 4 - 2 - 1 = 1.
      "80"    // Dynamic table entry with relative index 0, absolute index 0.
      "10"    // Dynamic table entry with post-base index 0, absolute index 1.
      "11"    // Dynamic table entry with post-base index 1, absolute index 2.
      "12"    // Dynamic table entry with post-base index 2, absolute index 3.
      "01025a5a"));  // Name of entry 1 (post-base index) from dynamic table,
                     // with value "ZZ".
}

TEST_P(QpackDecoderTest, DecreasingDynamicTableCapacityEvictsEntries) {
  // Set dynamic table capacity to 1024.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3fe107"));
  // Add literal entry with name "foo" and value "bar".
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
  EXPECT_CALL(handler_, OnDecodingCompleted());
  EXPECT_CALL(decoder_stream_sender_delegate_,
              WriteStreamData(Eq(kHeaderAcknowledgement)));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0200"   // Required Insert Count 1 and Delta Base 0.
               // Base is 1 + 0 = 1.
      "80"));  // Dynamic table entry with relative index 0, absolute index 0.

  // Change dynamic table capacity to 32 bytes, smaller than the entry.
  // This must cause the entry to be evicted.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3f01"));

  EXPECT_CALL(handler_, OnDecodingErrorDetected(
                            Eq("Dynamic table entry already evicted.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0200"   // Required Insert Count 1 and Delta Base 0.
               // Base is 1 + 0 = 1.
      "80"));  // Dynamic table entry with relative index 0, absolute index 0.
}

TEST_P(QpackDecoderTest, EncoderStreamErrorEntryTooLarge) {
  EXPECT_CALL(encoder_stream_error_delegate_,
              OnEncoderStreamError(Eq("Error inserting literal entry.")));

  // Set dynamic table capacity to 34.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3f03"));
  // Add literal entry with name "foo" and value "bar", size is 32 + 3 + 3 = 38.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));
}

TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidStaticTableEntry) {
  EXPECT_CALL(encoder_stream_error_delegate_,
              OnEncoderStreamError(Eq("Invalid static table entry.")));

  // Address invalid static table entry index 99.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("ff2400"));
}

TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidDynamicTableEntry) {
  EXPECT_CALL(encoder_stream_error_delegate_,
              OnEncoderStreamError(Eq("Invalid relative index.")));

  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode(
      "3fe107"          // Set dynamic table capacity to 1024.
      "6294e703626172"  // Add literal entry with name "foo" and value "bar".
      "8100"));  // Address dynamic table entry with relative index 1.  Such
                 // entry does not exist.  The most recently added and only
                 // dynamic table entry has relative index 0.
}

TEST_P(QpackDecoderTest, EncoderStreamErrorDuplicateInvalidEntry) {
  EXPECT_CALL(encoder_stream_error_delegate_,
              OnEncoderStreamError(Eq("Invalid relative index.")));

  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode(
      "3fe107"          // Set dynamic table capacity to 1024.
      "6294e703626172"  // Add literal entry with name "foo" and value "bar".
      "01"));  // Duplicate dynamic table entry with relative index 1.  Such
               // entry does not exist.  The most recently added and only
               // dynamic table entry has relative index 0.
}

TEST_P(QpackDecoderTest, EncoderStreamErrorTooLargeInteger) {
  EXPECT_CALL(encoder_stream_error_delegate_,
              OnEncoderStreamError(Eq("Encoded integer too large.")));

  DecodeEncoderStreamData(
      quiche::QuicheTextUtils::HexDecode("3fffffffffffffffffffff"));
}

TEST_P(QpackDecoderTest, InvalidDynamicEntryWhenBaseIsZero) {
  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));

  // Set dynamic table capacity to 1024.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3fe107"));
  // Add literal entry with name "foo" and value "bar".
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0280"   // Required Insert Count is 1.  Base 1 - 1 - 0 = 0 is explicitly
               // permitted by the spec.
      "80"));  // However, addressing entry with relative index 0 would point to
               // absolute index -1, which is invalid.
}

TEST_P(QpackDecoderTest, InvalidNegativeBase) {
  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Error calculating Base.")));

  // Required Insert Count 1, Delta Base 1 with sign bit set, Base would
  // be 1 - 1 - 1 = -1, but it is not allowed to be negative.
  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("0281"));
}

TEST_P(QpackDecoderTest, InvalidDynamicEntryByRelativeIndex) {
  // Set dynamic table capacity to 1024.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3fe107"));
  // Add literal entry with name "foo" and value "bar".
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));

  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0200"   // Required Insert Count 1 and Delta Base 0.
               // Base is 1 + 0 = 1.
      "81"));  // Indexed Header Field instruction addressing relative index 1.
               // This is absolute index -1, which is invalid.

  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0200"     // Required Insert Count 1 and Delta Base 0.
                 // Base is 1 + 0 = 1.
      "4100"));  // Literal Header Field with Name Reference instruction
                 // addressing relative index 1.  This is absolute index -1,
                 // which is invalid.
}

TEST_P(QpackDecoderTest, EvictedDynamicTableEntry) {
  // Update dynamic table capacity to 128.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3f61"));

  // Add literal entry with name "foo" and value "bar", size 32 + 3 + 3 = 38.
  // This fits in the table three times.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));
  // Duplicate entry four times.  This evicts the first two instances.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("00000000"));

  EXPECT_CALL(handler_, OnDecodingErrorDetected(
                            Eq("Dynamic table entry already evicted.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0500"   // Required Insert Count 4 and Delta Base 0.
               // Base is 4 + 0 = 4.
      "82"));  // Indexed Header Field instruction addressing relative index 2.
               // This is absolute index 1. Such entry does not exist.

  EXPECT_CALL(handler_, OnDecodingErrorDetected(
                            Eq("Dynamic table entry already evicted.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0500"     // Required Insert Count 4 and Delta Base 0.
                 // Base is 4 + 0 = 4.
      "4200"));  // Literal Header Field with Name Reference instruction
                 // addressing relative index 2.  This is absolute index 1. Such
                 // entry does not exist.

  EXPECT_CALL(handler_, OnDecodingErrorDetected(
                            Eq("Dynamic table entry already evicted.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0380"   // Required Insert Count 2 and Delta Base 0 with sign bit set.
               // Base is 2 - 0 - 1 = 1
      "10"));  // Indexed Header Field instruction addressing dynamic table
               // entry with post-base index 0, absolute index 1.  Such entry
               // does not exist.

  EXPECT_CALL(handler_, OnDecodingErrorDetected(
                            Eq("Dynamic table entry already evicted.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0380"     // Required Insert Count 2 and Delta Base 0 with sign bit set.
                 // Base is 2 - 0 - 1 = 1
      "0000"));  // Literal Header Field With Name Reference instruction
                 // addressing dynamic table entry with post-base index 0,
                 // absolute index 1.  Such entry does not exist.
}

TEST_P(QpackDecoderTest, TableCapacityMustNotExceedMaximum) {
  EXPECT_CALL(
      encoder_stream_error_delegate_,
      OnEncoderStreamError(Eq("Error updating dynamic table capacity.")));

  // Try to update dynamic table capacity to 2048, which exceeds the maximum.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3fe10f"));
}

TEST_P(QpackDecoderTest, SetDynamicTableCapacity) {
  // Update dynamic table capacity to 128, which does not exceed the maximum.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3f61"));
}

TEST_P(QpackDecoderTest, InvalidEncodedRequiredInsertCount) {
  // Maximum dynamic table capacity is 1024.
  // MaxEntries is 1024 / 32 = 32.
  // Required Insert Count is decoded modulo 2 * MaxEntries, that is, modulo 64.
  // A value of 1 cannot be encoded as 65 even though it has the same remainder.
  EXPECT_CALL(handler_, OnDecodingErrorDetected(
                            Eq("Error decoding Required Insert Count.")));
  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("4100"));
}

// Regression test for https://crbug.com/970218:  Decoder must stop processing
// after a Header Block Prefix with an invalid Encoded Required Insert Count.
TEST_P(QpackDecoderTest, DataAfterInvalidEncodedRequiredInsertCount) {
  EXPECT_CALL(handler_, OnDecodingErrorDetected(
                            Eq("Error decoding Required Insert Count.")));
  // Header Block Prefix followed by some extra data.
  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode("410000"));
}

TEST_P(QpackDecoderTest, WrappedRequiredInsertCount) {
  // Maximum dynamic table capacity is 1024.
  // MaxEntries is 1024 / 32 = 32.

  // Set dynamic table capacity to 1024.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3fe107"));
  // Add literal entry with name "foo" and a 600 byte long value.  This will fit
  // in the dynamic table once but not twice.
  DecodeEncoderStreamData(
      quiche::QuicheTextUtils::HexDecode("6294e7"     // Name "foo".
                                         "7fd903"));  // Value length 600.
  std::string header_value(600, 'Z');
  DecodeEncoderStreamData(header_value);

  // Duplicate most recent entry 200 times.
  DecodeEncoderStreamData(std::string(200, '\x00'));

  // Now there is only one entry in the dynamic table, with absolute index 200.

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq(header_value)));
  EXPECT_CALL(handler_, OnDecodingCompleted());
  EXPECT_CALL(decoder_stream_sender_delegate_,
              WriteStreamData(Eq(kHeaderAcknowledgement)));

  // Send header block with Required Insert Count = 201.
  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0a00"   // Encoded Required Insert Count 10, Required Insert Count 201,
               // Delta Base 0, Base 201.
      "80"));  // Emit dynamic table entry with relative index 0.
}

TEST_P(QpackDecoderTest, NonZeroRequiredInsertCountButNoDynamicEntries) {
  // Set dynamic table capacity to 1024.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3fe107"));
  // Add literal entry with name "foo" and value "bar".
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0200"   // Required Insert Count is 1.
      "d1"));  // But the only instruction references the static table.
}

TEST_P(QpackDecoderTest, AddressEntryNotAllowedByRequiredInsertCount) {
  // Set dynamic table capacity to 1024.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3fe107"));
  // Add literal entry with name "foo" and value "bar".
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));

  EXPECT_CALL(
      handler_,
      OnDecodingErrorDetected(
          Eq("Absolute Index must be smaller than Required Insert Count.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0201"   // Required Insert Count 1 and Delta Base 1.
               // Base is 1 + 1 = 2.
      "80"));  // Indexed Header Field instruction addressing dynamic table
               // entry with relative index 0, absolute index 1.  This is not
               // allowed by Required Insert Count.

  EXPECT_CALL(
      handler_,
      OnDecodingErrorDetected(
          Eq("Absolute Index must be smaller than Required Insert Count.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0201"     // Required Insert Count 1 and Delta Base 1.
                 // Base is 1 + 1 = 2.
      "4000"));  // Literal Header Field with Name Reference instruction
                 // addressing dynamic table entry with relative index 0,
                 // absolute index 1.  This is not allowed by Required Index
                 // Count.

  EXPECT_CALL(
      handler_,
      OnDecodingErrorDetected(
          Eq("Absolute Index must be smaller than Required Insert Count.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0200"   // Required Insert Count 1 and Delta Base 0.
               // Base is 1 + 0 = 1.
      "10"));  // Indexed Header Field with Post-Base Index instruction
               // addressing dynamic table entry with post-base index 0,
               // absolute index 1.  This is not allowed by Required Insert
               // Count.

  EXPECT_CALL(
      handler_,
      OnDecodingErrorDetected(
          Eq("Absolute Index must be smaller than Required Insert Count.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0200"     // Required Insert Count 1 and Delta Base 0.
                 // Base is 1 + 0 = 1.
      "0000"));  // Literal Header Field with Post-Base Name Reference
                 // instruction addressing dynamic table entry with post-base
                 // index 0, absolute index 1.  This is not allowed by Required
                 // Index Count.
}

TEST_P(QpackDecoderTest, PromisedRequiredInsertCountLargerThanActual) {
  // Set dynamic table capacity to 1024.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3fe107"));
  // Add literal entry with name "foo" and value "bar".
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));
  // Duplicate entry twice so that decoding of header blocks with Required
  // Insert Count not exceeding 3 is not blocked.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("00"));
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("00"));

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0300"   // Required Insert Count 2 and Delta Base 0.
               // Base is 2 + 0 = 2.
      "81"));  // Indexed Header Field instruction addressing dynamic table
               // entry with relative index 1, absolute index 0.  Header block
               // requires insert count of 1, even though Required Insert Count
               // is 2.

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0300"     // Required Insert Count 2 and Delta Base 0.
                 // Base is 2 + 0 = 2.
      "4100"));  // Literal Header Field with Name Reference instruction
                 // addressing dynamic table entry with relative index 1,
                 // absolute index 0.  Header block requires insert count of 1,
                 // even though Required Insert Count is 2.

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0481"   // Required Insert Count 3 and Delta Base 1 with sign bit set.
               // Base is 3 - 1 - 1 = 1.
      "10"));  // Indexed Header Field with Post-Base Index instruction
               // addressing dynamic table entry with post-base index 0,
               // absolute index 1.  Header block requires insert count of 2,
               // even though Required Insert Count is 3.

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
  EXPECT_CALL(handler_,
              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0481"     // Required Insert Count 3 and Delta Base 1 with sign bit set.
                 // Base is 3 - 1 - 1 = 1.
      "0000"));  // Literal Header Field with Post-Base Name Reference
                 // instruction addressing dynamic table entry with post-base
                 // index 0, absolute index 1.  Header block requires insert
                 // count of 2, even though Required Insert Count is 3.
}

TEST_P(QpackDecoderTest, BlockedDecoding) {
  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0200"   // Required Insert Count 1 and Delta Base 0.
               // Base is 1 + 0 = 1.
      "80"));  // Indexed Header Field instruction addressing dynamic table
               // entry with relative index 0, absolute index 0.

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
  EXPECT_CALL(handler_, OnDecodingCompleted());
  EXPECT_CALL(decoder_stream_sender_delegate_,
              WriteStreamData(Eq(kHeaderAcknowledgement)));

  // Set dynamic table capacity to 1024.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3fe107"));
  // Add literal entry with name "foo" and value "bar".
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));
}

TEST_P(QpackDecoderTest, BlockedDecodingUnblockedBeforeEndOfHeaderBlock) {
  StartDecoding();
  DecodeData(quiche::QuicheTextUtils::HexDecode(
      "0200"   // Required Insert Count 1 and Delta Base 0.
               // Base is 1 + 0 = 1.
      "80"     // Indexed Header Field instruction addressing dynamic table
               // entry with relative index 0, absolute index 0.
      "d1"));  // Static table entry with index 17.

  // Set dynamic table capacity to 1024.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3fe107"));

  // Add literal entry with name "foo" and value "bar".  Decoding is now
  // unblocked because dynamic table Insert Count reached the Required Insert
  // Count of the header block.  |handler_| methods are called immediately for
  // the already consumed part of the header block.
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));
  Mock::VerifyAndClearExpectations(&handler_);

  // Rest of header block is processed by QpackProgressiveDecoder
  // in the unblocked state.
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":scheme"), Eq("https")));
  DecodeData(quiche::QuicheTextUtils::HexDecode(
      "80"     // Indexed Header Field instruction addressing dynamic table
               // entry with relative index 0, absolute index 0.
      "d7"));  // Static table entry with index 23.
  Mock::VerifyAndClearExpectations(&handler_);

  EXPECT_CALL(handler_, OnDecodingCompleted());
  EXPECT_CALL(decoder_stream_sender_delegate_,
              WriteStreamData(Eq(kHeaderAcknowledgement)));
  EndDecoding();
}

// Regression test for https://crbug.com/1024263.
TEST_P(QpackDecoderTest,
       BlockedDecodingUnblockedAndErrorBeforeEndOfHeaderBlock) {
  StartDecoding();
  DecodeData(quiche::QuicheTextUtils::HexDecode(
      "0200"   // Required Insert Count 1 and Delta Base 0.
               // Base is 1 + 0 = 1.
      "80"     // Indexed Header Field instruction addressing dynamic table
               // entry with relative index 0, absolute index 0.
      "81"));  // Relative index 1 is equal to Base, therefore invalid.

  // Set dynamic table capacity to 1024.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3fe107"));

  // Add literal entry with name "foo" and value "bar".  Decoding is now
  // unblocked because dynamic table Insert Count reached the Required Insert
  // Count of the header block.  |handler_| methods are called immediately for
  // the already consumed part of the header block.
  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));
}

// Make sure that Required Insert Count is compared to Insert Count,
// not size of dynamic table.
TEST_P(QpackDecoderTest, BlockedDecodingAndEvictedEntries) {
  // Update dynamic table capacity to 128.
  // At most three non-empty entries fit in the dynamic table.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("3f61"));

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0700"   // Required Insert Count 6 and Delta Base 0.
               // Base is 6 + 0 = 6.
      "80"));  // Indexed Header Field instruction addressing dynamic table
               // entry with relative index 0, absolute index 5.

  // Add literal entry with name "foo" and value "bar".
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e703626172"));

  // Duplicate entry four times.  This evicts the first two instances.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("00000000"));

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("baz")));
  EXPECT_CALL(handler_, OnDecodingCompleted());
  EXPECT_CALL(decoder_stream_sender_delegate_,
              WriteStreamData(Eq(kHeaderAcknowledgement)));

  // Add literal entry with name "foo" and value "bar".
  // Insert Count is now 6, reaching Required Insert Count of the header block.
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode("6294e70362617a"));
}

TEST_P(QpackDecoderTest, TooManyBlockedStreams) {
  // Required Insert Count 1 and Delta Base 0.
  // Without any dynamic table entries received, decoding is blocked.
  std::string data = quiche::QuicheTextUtils::HexDecode("0200");

  auto progressive_decoder1 = CreateProgressiveDecoder(/* stream_id = */ 1);
  progressive_decoder1->Decode(data);

  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq(
                            "Limit on number of blocked streams exceeded.")));

  auto progressive_decoder2 = CreateProgressiveDecoder(/* stream_id = */ 2);
  progressive_decoder2->Decode(data);
}

TEST_P(QpackDecoderTest, InsertCountIncrement) {
  DecodeEncoderStreamData(quiche::QuicheTextUtils::HexDecode(
      "3fe107"          // Set dynamic table capacity to 1024.
      "6294e703626172"  // Add literal entry with name "foo" and value "bar".
      "00"));           // Duplicate entry.

  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
  EXPECT_CALL(handler_, OnDecodingCompleted());

  // Decoder received two insertions, but Header Acknowledgement only increases
  // Known Insert Count to one.  Decoder should send an Insert Count Increment
  // instruction with increment of one to update Known Insert Count to two.
  EXPECT_CALL(decoder_stream_sender_delegate_,
              WriteStreamData(Eq(quiche::QuicheTextUtils::HexDecode(
                  "81"       // Header Acknowledgement on stream 1
                  "01"))));  // Insert Count Increment with increment of one

  DecodeHeaderBlock(quiche::QuicheTextUtils::HexDecode(
      "0200"   // Required Insert Count 1 and Delta Base 0.
               // Base is 1 + 0 = 1.
      "80"));  // Dynamic table entry with relative index 0, absolute index 0.
}

}  // namespace
}  // namespace test
}  // namespace quic
